#ifndef PACKET_H
#define PACKET_H

#include <cstdint>

extern "C"{

#pragma pack(1)

struct PacketHeader
{
    uint16_t  m_packetFormat;         // 2019
    uint8_t   m_gameMajorVersion;     // Game major version - "X.00"
    uint8_t   m_gameMinorVersion;     // Game minor version - "1.XX"
    uint8_t   m_packetVersion;        // Version of this packet type, all start from 1
    uint8_t   m_packetId;             // Identifier for the packet type, see below
    uint64_t  m_sessionUID;           // Unique identifier for the session
    float     m_sessionTime;          // Session timestamp
    uint32_t  m_frameIdentifier;      // Identifier for the frame the data was retrieved on
    uint8_t   m_playerCarIndex;       // Index of player's car in the array
};


enum PacketID{
    PKT_MOTION = 0,
    PKT_SEESION,
    PKT_LAP_DATA,
    PKT_EVENT,
    PKT_PARTICIPANTS,
    PKT_CAR_SETUPS,
    PKT_CAR_TELEMETRY,
    PKT_CAR_STATUS,
};

struct CarMotionData
{
    float         m_worldPositionX;           // World space X position
    float         m_worldPositionY;           // World space Y position
    float         m_worldPositionZ;           // World space Z position
    float         m_worldVelocityX;           // Velocity in world space X
    float         m_worldVelocityY;           // Velocity in world space Y
    float         m_worldVelocityZ;           // Velocity in world space Z
    int16_t       m_worldForwardDirX;         // World space forward X direction (normalised)
    int16_t       m_worldForwardDirY;         // World space forward Y direction (normalised)
    int16_t       m_worldForwardDirZ;         // World space forward Z direction (normalised)
    int16_t       m_worldRightDirX;           // World space right X direction (normalised)
    int16_t       m_worldRightDirY;           // World space right Y direction (normalised)
    int16_t       m_worldRightDirZ;           // World space right Z direction (normalised)
    float         m_gForceLateral;            // Lateral G-Force component
    float         m_gForceLongitudinal;       // Longitudinal G-Force component
    float         m_gForceVertical;           // Vertical G-Force component
    float         m_yaw;                      // Yaw angle in radians
    float         m_pitch;                    // Pitch angle in radians
    float         m_roll;                     // Roll angle in radians
};

struct PacketMotionData
{
    PacketHeader    m_header;                // Header

    CarMotionData   m_carMotionData[20];     // Data for all cars on track

    // Extra player car ONLY data
    float         m_suspensionPosition[4];       // Note: All wheel arrays have the following order:
    float         m_suspensionVelocity[4];       // RL, RR, FL, FR
    float         m_suspensionAcceleration[4];   // RL, RR, FL, FR
    float         m_wheelSpeed[4];               // Speed of each wheel
    float         m_wheelSlip[4];                // Slip ratio for each wheel
    float         m_localVelocityX;              // Velocity in local space
    float         m_localVelocityY;              // Velocity in local space
    float         m_localVelocityZ;              // Velocity in local space
    float         m_angularVelocityX;            // Angular velocity x-component
    float         m_angularVelocityY;            // Angular velocity y-component
    float         m_angularVelocityZ;            // Angular velocity z-component
    float         m_angularAccelerationX;        // Angular acceleration x-component
    float         m_angularAccelerationY;        // Angular acceleration y-component
    float         m_angularAccelerationZ;        // Angular acceleration z-component
    float         m_frontWheelsAngle;            // Current front wheels angle in radians
};

struct MarshalZone
{
    float  m_zoneStart;   // Fraction (0..1) of way through the lap the marshal zone starts
    int8_t   m_zoneFlag;    // -1 = invalid/unknown, 0 = none, 1 = green, 2 = blue, 3 = yellow, 4 = red
};

struct PacketSessionData
{
    PacketHeader    m_header;                // Header

    uint8_t         m_weather;               // Weather - 0 = clear, 1 = light cloud, 2 = overcast
    // 3 = light rain, 4 = heavy rain, 5 = storm
    int8_t          m_trackTemperature;      // Track temp. in degrees celsius
    int8_t          m_airTemperature;        // Air temp. in degrees celsius
    uint8_t         m_totalLaps;             // Total number of laps in this race
    uint16_t        m_trackLength;           // Track length in metres
    uint8_t         m_sessionType;           // 0 = unknown, 1 = P1, 2 = P2, 3 = P3, 4 = Short P
    // 5 = Q1, 6 = Q2, 7 = Q3, 8 = Short Q, 9 = OSQ
    // 10 = R, 11 = R2, 12 = Time Trial
    int8_t          m_trackId;               // -1 for unknown, 0-21 for tracks, see appendix
    uint8_t         m_formula;               // Formula, 0 = F1 Modern, 1 = F1 Classic, 2 = F2,
    // 3 = F1 Generic
    uint16_t        m_sessionTimeLeft;       // Time left in session in seconds
    uint16_t        m_sessionDuration;       // Session duration in seconds
    uint8_t         m_pitSpeedLimit;         // Pit speed limit in kilometres per hour
    uint8_t         m_gamePaused;            // Whether the game is paused
    uint8_t         m_isSpectating;          // Whether the player is spectating
    uint8_t         m_spectatorCarIndex;     // Index of the car being spectated
    uint8_t         m_sliProNativeSupport;   // SLI Pro support, 0 = inactive, 1 = active
    uint8_t         m_numMarshalZones;       // Number of marshal zones to follow
    MarshalZone     m_marshalZones[21];      // List of marshal zones – max 21
    uint8_t         m_safetyCarStatus;       // 0 = no safety car, 1 = full safety car
    // 2 = virtual safety car
    uint8_t         m_networkGame;           // 0 = offline, 1 = online
};

struct LapData
{
    float       m_lastLapTime;               // Last lap time in seconds
    float       m_currentLapTime;            // Current time around the lap in seconds
    float       m_bestLapTime;               // Best lap time of the session in seconds
    float       m_sector1Time;               // Sector 1 time in seconds
    float       m_sector2Time;               // Sector 2 time in seconds
    float       m_lapDistance;               // Distance vehicle is around current lap in metres – could
    // be negative if line hasn’t been crossed yet
    float       m_totalDistance;             // Total distance travelled in session in metres – could
    // be negative if line hasn’t been crossed yet
    float       m_safetyCarDelta;            // Delta in seconds for safety car
    uint8_t     m_carPosition;               // Car race position
    uint8_t     m_currentLapNum;             // Current lap number
    uint8_t     m_pitStatus;                 // 0 = none, 1 = pitting, 2 = in pit area
    uint8_t     m_sector;                    // 0 = sector1, 1 = sector2, 2 = sector3
    uint8_t     m_currentLapInvalid;         // Current lap invalid - 0 = valid, 1 = invalid
    uint8_t     m_penalties;                 // Accumulated time penalties in seconds to be added
    uint8_t     m_gridPosition;              // Grid position the vehicle started the race in
    uint8_t     m_driverStatus;              // Status of driver - 0 = in garage, 1 = flying lap
    // 2 = in lap, 3 = out lap, 4 = on track
    uint8_t     m_resultStatus;              // Result status - 0 = invalid, 1 = inactive, 2 = active
    // 3 = finished, 4 = disqualified, 5 = not classified
    // 6 = retired
};

struct PacketLapData
{
    PacketHeader    m_header;              // Header

    LapData         m_lapData[20];         // Lap data for all cars on track
};

// The event details packet is different for each type of event.
// Make sure only the correct type is interpreted.

union EventDataDetails
{
    struct
    {
        uint8_t      vehicleIdx; // Vehicle index of car achieving fastest lap
        float        lapTime;    // Lap time is in seconds
    } FastestLap;

    struct
    {
        uint8_t vehicleIdx; // Vehicle index of car retiring
    } Retirement;

    struct
    {
        uint8_t vehicleIdx; // Vehicle index of team mate
    } TeamMateInPits;

    struct
    {
        uint8_t vehicleIdx; // Vehicle index of the race winner
    } RaceWinner;
};

struct PacketEventData
{
    PacketHeader     m_header;               // Header

    uint8_t          m_eventStringCode[4];   // Event string code, see below
    /*
     *

    “SSTA” Sent when the session starts
    “SEND” Sent when the session ends
    “FTLP” When a driver achieves the fastest lap
    “RTMT” When a driver retires
    “DRSE” Race control have enabled DRS
    “DRSD” Race control have disabled DRS
    “TMPT” Your team mate has entered the pits
    “CHQF” The chequered flag has been waved
    “RCWN” The race winner is announced
     *
     *
     */


    EventDataDetails m_eventDetails;         // Event details - should be interpreted differently
};

struct ParticipantData
{
    uint8_t    m_aiControlled;           // Whether the vehicle is AI (1) or Human (0) controlled
    uint8_t    m_driverId;               // Driver id - see appendix
    uint8_t    m_teamId;                 // Team id - see appendix
    uint8_t    m_raceNumber;             // Race number of the car
    uint8_t    m_nationality;            // Nationality of the driver
    char       m_name[48];               // Name of participant in UTF-8 format – null terminated
    // Will be truncated with … (U+2026) if too long
    uint8_t    m_yourTelemetry;          // The player's UDP setting, 0 = restricted, 1 = public
};

struct PacketParticipantsData
{
    PacketHeader    m_header;            // Header

    uint8_t           m_numActiveCars;     // Number of active cars in the data – should match number of
    // cars on HUD
    ParticipantData m_participants[20];
};

struct CarSetupData
{
    uint8_t   m_frontWing;                // Front wing aero
    uint8_t   m_rearWing;                 // Rear wing aero
    uint8_t   m_onThrottle;               // Differential adjustment on throttle (percentage)
    uint8_t   m_offThrottle;              // Differential adjustment off throttle (percentage)
    float     m_frontCamber;              // Front camber angle (suspension geometry)
    float     m_rearCamber;               // Rear camber angle (suspension geometry)
    float     m_frontToe;                 // Front toe angle (suspension geometry)
    float     m_rearToe;                  // Rear toe angle (suspension geometry)
    uint8_t   m_frontSuspension;          // Front suspension
    uint8_t   m_rearSuspension;           // Rear suspension
    uint8_t   m_frontAntiRollBar;         // Front anti-roll bar
    uint8_t   m_rearAntiRollBar;          // Rear anti-roll bar
    uint8_t   m_frontSuspensionHeight;    // Front ride height
    uint8_t   m_rearSuspensionHeight;     // Rear ride height
    uint8_t   m_brakePressure;            // Brake pressure (percentage)
    uint8_t   m_brakeBias;                // Brake bias (percentage)
    float     m_frontTyrePressure;        // Front tyre pressure (PSI)
    float     m_rearTyrePressure;         // Rear tyre pressure (PSI)
    uint8_t   m_ballast;                  // Ballast
    float     m_fuelLoad;                 // Fuel load
};

struct PacketCarSetupData
{
    PacketHeader    m_header;            // Header

    CarSetupData    m_carSetups[20];
};

struct CarTelemetryData
{
    uint16_t  m_speed;                    // Speed of car in kilometres per hour
    float     m_throttle;                 // Amount of throttle applied (0.0 to 1.0)
    float     m_steer;                    // Steering (-1.0 (full lock left) to 1.0 (full lock right))
    float     m_brake;                    // Amount of brake applied (0.0 to 1.0)
    uint8_t   m_clutch;                   // Amount of clutch applied (0 to 100)
    int8_t    m_gear;                     // Gear selected (1-8, N=0, R=-1)
    uint16_t  m_engineRPM;                // Engine RPM
    uint8_t   m_drs;                      // 0 = off, 1 = on
    uint8_t   m_revLightsPercent;         // Rev lights indicator (percentage)
    uint16_t  m_brakesTemperature[4];     // Brakes temperature (celsius)
    uint16_t  m_tyresSurfaceTemperature[4]; // Tyres surface temperature (celsius)
    uint16_t  m_tyresInnerTemperature[4]; // Tyres inner temperature (celsius)
    uint16_t  m_engineTemperature;        // Engine temperature (celsius)
    float     m_tyresPressure[4];         // Tyres pressure (PSI)
    uint8_t   m_surfaceType[4];           // Driving surface, see appendices
};

struct PacketCarTelemetryData
{
    PacketHeader     m_header;             // Header

    CarTelemetryData m_carTelemetryData[20];

    uint32_t         m_buttonStatus;        // Bit flags specifying which buttons are being pressed
    // currently - see appendices
};


struct CarStatusData
{
    uint8_t     m_tractionControl;          // 0 (off) - 2 (high)
    uint8_t     m_antiLockBrakes;           // 0 (off) - 1 (on)
    uint8_t     m_fuelMix;                  // Fuel mix - 0 = lean, 1 = standard, 2 = rich, 3 = max
    uint8_t     m_frontBrakeBias;           // Front brake bias (percentage)
    uint8_t     m_pitLimiterStatus;         // Pit limiter status - 0 = off, 1 = on
    float       m_fuelInTank;               // Current fuel mass
    float       m_fuelCapacity;             // Fuel capacity
    float       m_fuelRemainingLaps;        // Fuel remaining in terms of laps (value on MFD)
    uint16_t    m_maxRPM;                   // Cars max RPM, point of rev limiter
    uint16_t    m_idleRPM;                  // Cars idle RPM
    uint8_t     m_maxGears;                 // Maximum number of gears
    uint8_t     m_drsAllowed;               // 0 = not allowed, 1 = allowed, -1 = unknown
    uint8_t     m_tyresWear[4];             // Tyre wear percentage
    uint8_t     m_actualTyreCompound;       // F1 Modern - 16 = C5, 17 = C4, 18 = C3, 19 = C2, 20 = C1
    // 7 = inter, 8 = wet
    // F1 Classic - 9 = dry, 10 = wet
    // F2 – 11 = super soft, 12 = soft, 13 = medium, 14 = hard
    // 15 = wet
    uint8_t     m_tyreVisualCompound;       // F1 visual (can be different from actual compound)
    // 16 = soft, 17 = medium, 18 = hard, 7 = inter, 8 = wet
    // F1 Classic – same as above
    // F2 – same as above
    uint8_t     m_tyresDamage[4];           // Tyre damage (percentage)
    uint8_t     m_frontLeftWingDamage;      // Front left wing damage (percentage)
    uint8_t     m_frontRightWingDamage;     // Front right wing damage (percentage)
    uint8_t     m_rearWingDamage;           // Rear wing damage (percentage)
    uint8_t     m_engineDamage;             // Engine damage (percentage)
    uint8_t     m_gearBoxDamage;            // Gear box damage (percentage)
    int8_t      m_vehicleFiaFlags;          // -1 = invalid/unknown, 0 = none, 1 = green
    // 2 = blue, 3 = yellow, 4 = red
    float       m_ersStoreEnergy;           // ERS energy store in Joules
    uint8_t     m_ersDeployMode;            // ERS deployment mode, 0 = none, 1 = low, 2 = medium
    // 3 = high, 4 = overtake, 5 = hotlap
    float       m_ersHarvestedThisLapMGUK;  // ERS energy harvested this lap by MGU-K
    float       m_ersHarvestedThisLapMGUH;  // ERS energy harvested this lap by MGU-H
    float       m_ersDeployedThisLap;       // ERS energy deployed this lap
};

struct PacketCarStatusData
{
    PacketHeader     m_header;          // Header

    CarStatusData    m_carStatusData[20];
};

#pragma pack()

} // extern "C"

#endif // PACKET_H
